﻿using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamasoft.JsonClassGenerator.CodeWriters;
using Xamasoft.JsonClassGenerator;
using ICSharpCode.AvalonEdit.Document;
using System.Windows.Markup;
using CommunityToolkit.Mvvm.Input;
using Newtonsoft.Json;
using HandyControl.Controls;
using HandyControl.Tools.Extension;

namespace CSharpDevTools.ViewModels
{
    internal class JsonControlViewModel : ObservableObject
    {
        private readonly static ICodeWriter[] fCodeWriters = new ICodeWriter[] {
            new CSharpCodeWriter(),
            new VisualBasicCodeWriter(),
            new TypeScriptCodeWriter()
        };

        #region 属性
        private string classNamespace = "Example";

        public string ClassNameSpace
        {
            get { return this.classNamespace; }
            set
            {
                if (this.SetProperty(ref this.classNamespace, value))
                {
                    this.UpdateStatus();
                }
            }
        }

        private string className = "SampleResponse1";

        public string ClassName
        {
            get { return className; }
            set
            {
                if (this.SetProperty(ref this.className, value))
                {
                    this.UpdateStatus();
                }
            }
        }

        private string saveDir;

        public string SaveDir
        {
            get { return saveDir; }
            set { this.SetProperty(ref this.saveDir, value); }
        }

        public ICodeWriter[] CodeWriters
        {
            get
            {
                return fCodeWriters;
            }
        }

        private ICodeWriter selectedCodeWriter = fCodeWriters.FirstOrDefault();

        public ICodeWriter SelectedCodeWriter
        {
            get { return selectedCodeWriter; }
            set
            {
                if (this.SetProperty(ref this.selectedCodeWriter, value))
                {
                    this.UpdateStatus();
                }
            }
        }

        private bool useNestedClasses = false;

        public bool UseNestedClasses
        {
            get { return useNestedClasses; }
            set
            {
                if (this.SetProperty(ref this.useNestedClasses, value))
                {
                    this.UpdateStatus();
                }
            }
        }

        private bool useSameNamespace = false;

        public bool UseSameNamespace
        {
            get { return useSameNamespace; }
            set
            {
                if (this.SetProperty(ref this.useSameNamespace, value))
                {
                    this.UpdateStatus();
                }
            }
        }

        private bool useDifferentNamespace = true;

        public bool UseDifferentNamespace
        {
            get { return useDifferentNamespace; }
            set
            {
                if (this.SetProperty(ref this.useDifferentNamespace, value))
                {
                    this.UpdateStatus();
                }
            }
        }

        private string secondaryNamespace = "Example.JsonTypes";

        public string SecondaryNamespace
        {
            get { return secondaryNamespace; }
            set { this.SetProperty(ref this.secondaryNamespace, value); }
        }

        private bool useProperties = true;

        public bool UseProperties
        {
            get { return useProperties; }
            set { this.SetProperty(ref this.useProperties, value); }
        }

        private bool useFields = false;

        public bool UseFields
        {
            get { return useFields; }
            set { this.SetProperty(ref this.useFields, value); }
        }

        private bool useInternal = true;

        public bool UseInternal
        {
            get { return useInternal; }
            set { this.SetProperty(ref this.useInternal, value); }
        }

        private bool usePublic = false;

        public bool UsePublic
        {
            get { return usePublic; }
            set { this.SetProperty(ref this.usePublic, value); }
        }

        private bool convertPascalCase = true;

        public bool ConvertPascalCase
        {
            get { return convertPascalCase; }
            set { this.SetProperty(ref this.convertPascalCase, value); }
        }

        private bool sortMembers = true;

        public bool SortMembers
        {
            get { return sortMembers; }
            set { this.SetProperty(ref this.sortMembers, value); }
        }

        private bool deduplicate = false;

        public bool Deduplicate
        {
            get { return deduplicate; }
            set { this.SetProperty(ref this.deduplicate, value); }
        }

        private bool explicitDeserialization;

        public bool ExplicitDeserialization
        {
            get { return explicitDeserialization; }
            set
            {
                if (this.SetProperty(ref this.explicitDeserialization, value))
                {
                    this.UpdateStatus();
                }
            }
        }

        private bool noHelper;

        public bool NoHelper
        {
            get { return noHelper; }
            set { this.SetProperty(ref this.noHelper, value); }
        }

        private bool applyObfuscationAttributes;

        public bool ApplyObfuscationAttributes
        {
            get { return applyObfuscationAttributes; }
            set { this.SetProperty(ref this.applyObfuscationAttributes, value); }
        }

        private bool singleFile = false;

        public bool SingleFile
        {
            get { return singleFile; }
            set { this.SetProperty(ref this.singleFile, value); }
        }

        private bool documentationExamples = false;

        public bool DocumentationExamples
        {
            get { return documentationExamples; }
            set { this.SetProperty(ref this.documentationExamples, value); }
        }

        private TextDocument json = new TextDocument();

        public TextDocument Json
        {
            get { return json; }
            set { this.SetProperty(ref this.json, value); }
        }

        private bool secondaryNamespaceEnabled;

        public bool SecondaryNamespaceEnabled
        {
            get { return secondaryNamespaceEnabled; }
            set { this.SetProperty(ref this.secondaryNamespaceEnabled, value); }
        }

        private bool pascalCaseEnabled;

        public bool PascalCaseEnabled
        {
            get { return pascalCaseEnabled; }
            set { this.SetProperty(ref this.pascalCaseEnabled, value); }
        }

        private bool explicitDeserializationEnabled;

        public bool ExplicitDeserializationEnabled
        {
            get { return explicitDeserializationEnabled; }
            set { this.SetProperty(ref this.explicitDeserializationEnabled, value); }
        }

        private bool noHelperEnabled;

        public bool NoHelperEnabled
        {
            get { return noHelperEnabled; }
            set { this.SetProperty(ref this.noHelperEnabled, value); }
        }

        private System.Windows.Visibility showLoading = System.Windows.Visibility.Collapsed;

        public System.Windows.Visibility ShowLoading
        {
            get { return showLoading; }
            set { showLoading = value; }
        }

        #endregion

        #region 命令
        public RelayCommand BeautifyCmd => new RelayCommand(this.Beautify);

        public RelayCommand GenerateCmd => new RelayCommand(this.Generate);

        public RelayCommand SelectFolderCmd => new RelayCommand(this.SelectFolder);
        #endregion

        private void SelectFolder()
        {
            System.Windows.Forms.FolderBrowserDialog folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
            if (folderBrowserDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.SaveDir = folderBrowserDialog.SelectedPath;
            }
        }

        private void Beautify()
        {
            dynamic parsedJson = JsonConvert.DeserializeObject(this.Json.Text);
            this.Json.Text = JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
        }

        private void Generate()
        {
            if (this.SaveDir == string.Empty)
            {
                MessageBox.Error("请设置保存路径！", "错误");
                return;
            }

            if (this.ClassNameSpace == string.Empty)
            {
                MessageBox.Error("请设置命名空间！", "错误");
                return;
            }

            var gen = Prepare();
            if (gen == null) return;
            try
            {
                this.ShowLoading = System.Windows.Visibility.Visible;
                gen.GenerateClasses();
                MessageBox.Success("生成代码成功");
            }
            catch (Exception ex)
            {
                MessageBox.Error("生成代码错误: " + ex.Message, "错误");
            }
            finally
            {
                this.ShowLoading = System.Windows.Visibility.Collapsed;
                gen.FeedBack = null;
            }
        }

        private JsonClassGenerator Prepare()
        {
            if (this.Json.Text == string.Empty)
            {
                MessageBox.Error("请输入JSON字符串", "错误");
                return null;
            }


            if (this.ClassName == string.Empty)
            {
                MessageBox.Show("请设置类名", "错误");
                return null;
            }

            var gen = new JsonClassGenerator
            {
                Example = this.Json.Text,
                InternalVisibility = this.UseInternal,
                CodeWriter = this.SelectedCodeWriter,
                DeduplicateClasses = this.Deduplicate,
                TargetFolder = this.SaveDir,
                UseProperties = this.UseProperties,
                MainClass = this.ClassName,
                SortMemberFields = this.SortMembers,
                UsePascalCase = this.ConvertPascalCase,
                UseNestedClasses = this.UseNestedClasses,
                ApplyObfuscationAttributes = this.ApplyObfuscationAttributes,
                SingleFile = this.SingleFile,
                ExamplesInDocumentation = this.DocumentationExamples,
                Namespace = string.IsNullOrEmpty(this.ClassNameSpace) ? null : this.ClassNameSpace,
                NoHelperClass = this.NoHelper,
                SecondaryNamespace = this.UseDifferentNamespace && !string.IsNullOrEmpty(this.SecondaryNamespace) ? this.SecondaryNamespace : null,
            };
            gen.ExplicitDeserialization = this.ExplicitDeserialization && gen.CodeWriter is CSharpCodeWriter;

            return gen;
        }

        private void UpdateStatus()
        {
            if (this.SecondaryNamespace.Contains("JsonTypes") || this.SecondaryNamespace == string.Empty)
            {
                this.SecondaryNamespace = this.ClassNameSpace == string.Empty ? string.Empty : this.ClassNameSpace + "." + this.ClassName + "JsonTypes";
            }

            this.SecondaryNamespaceEnabled = this.useDifferentNamespace;
            this.PascalCaseEnabled = !(this.SelectedCodeWriter is TypeScriptCodeWriter);
            this.ExplicitDeserializationEnabled = this.SelectedCodeWriter is CSharpCodeWriter;
            this.NoHelperEnabled = this.ExplicitDeserializationEnabled && this.ExplicitDeserialization;
        }
    }
}
